﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using microsoft_TODO.MongoCore;
using microsoft_TODO.MongoCore.Repositories;
using microsoft_TODO.ServiceCore;
using microsoft_TODO.ServiceCore.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.IdentityModel.Tokens;
using Swashbuckle.AspNetCore.Swagger;

namespace microsoft_TODO {
    public class Startup {
        public Startup (IConfiguration configuration, IHostingEnvironment env) {
            var builder = new ConfigurationBuilder ().SetBasePath (env.ContentRootPath)
                .AddJsonFile ("appsettings.json", true, true)
                .AddJsonFile ($"appsettings.{env.EnvironmentName}.json", true)
                .AddEnvironmentVariables ();
            Configuration = builder.Build ();
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices (IServiceCollection services) {

            services.AddMvc (config => {
                // authorize all the things
                var policy = new AuthorizationPolicyBuilder ()
                    .RequireAuthenticatedUser ()
                    .Build ();
                config.Filters.Add (new AuthorizeFilter (policy));
            });

            services.AddAutoMapper ();

            services.AddSwaggerGen (u => {
                u.SwaggerDoc ("DEFAULT", new Info { Title = "microsoft-todo api", Version = "v1" });

                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                var xmlPath = Path.Combine (basePath, "TodoApi.xml");
                u.IncludeXmlComments (xmlPath);
            });

            ConfigureAuthenticationService (services);

            services.AddTransient<IListRepository, ListRepository> ();
            services.AddTransient<IUserRepository, UserRepository> ();
            services.AddTransient<ITaskRepository, TaskRepository> ();
            services.AddTransient<IUserService, UserService> ();
            services.AddTransient<IListService, ListService> ();
            services.AddTransient<ITaskService, TaskService> ();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure (IApplicationBuilder app, IHostingEnvironment env) {
            if (env.IsDevelopment ()) {
                app.UseDeveloperExceptionPage ();
            }

            app.UseAuthentication ();

            app.UseDefaultFiles ();
            app.UseStaticFiles ();

            // use swagger 需要在 use mvc 之前
            app.UseSwagger (u => {
                u.RouteTemplate = "api-docs/{documentName}/swagger.json";
            });
            app.UseSwaggerUI (u => {
                u.SwaggerEndpoint ("/api-docs/DEFAULT/swagger.json", "default api");
            });

            app.UseMvc (routes => {
                routes.MapRoute (
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}"
                );

                routes.MapSpaFallbackRoute (
                    name: "spa-fallback",
                    defaults: new { controller = "Home", action = "Index" }
                );
            });
        }

        private void ConfigureAuthenticationService (IServiceCollection services) {
            var jwtConfig = Configuration.GetSection ("Jwt");
            var secret = jwtConfig["Secret"];
            var key = Encoding.UTF8.GetBytes (secret);
            services.AddAuthentication (u => {
                    u.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    u.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer (u => {
                    u.SaveToken = true;
                    u.TokenValidationParameters = new TokenValidationParameters {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey (key),
                        ValidateIssuer = false,
                        ValidateAudience = false
                    };
                });
        }
    }
}